#include "video.h"
#include "game.h"

#include "pjaser/kung.h"
#include "pjaser/dam.h"
#include "pjaser/torn.h"
#include "pjaser/lopare.h"
#include "pjaser/hast.h"
#include "pjaser/bonde.h"

Game* game = NULL;

/*---------------------------------

Game::Game( void )
overloadad
Konstruktor när ett helt nytt spel skapas.

---------------------------------*/

Game::Game( void ) : markerad( NULL ), runda( 1 ), vemsDrag( 0 ), promovering( NULL ) {
	if( game ) delete game; game = this;

	// Nollställ arrayen med pjäser, eftersom inga pjäser finns än
	for( int i = 0; i < 8; i++ ) {
		for( int j = 0; j < 8; j++ ) {
			pjasArray[i][j] = NULL;
		}
	}

	// Öppna en gamelog, där alla spelets drag sparas.
	gamelog.open( "gamelog.txt" );
	gamelog << "detta är en gamelog\n";
	gamelog.flush();

	// Skapa spelarna. Pjäserna skapas i spelare-konstruktorn.
	spelare[VIT] = new Spelare( VIT );
	spelare[SVART] = new Spelare( SVART );

	// Kör kollaDrag, så vi vet vilka pjäser som kan gå vart
	// (Den för svart behövs "egentligen" inte, men om vi ska skapa AI
	// kanske datorn blir glad. Haha!)
	spelare[VIT]->kollaDrag();
	spelare[SVART]->kollaDrag();
}

/*---------------------------------

Game::Game( std::ifstream sparadFil )
overloadad
Konstruktor när ett spel laddas.
Argument: sparadFil = filen från vilken speldatat inläses.

---------------------------------*/

Game::Game( std::ifstream& sparadFil ) : markerad( NULL ), runda( 1 ), vemsDrag( 0 ), promovering( NULL ) {
	delete game, game = this;

	int tempArray[8][8];
	for( int i=0; i<8; i++ ) for( int j=0; j<8; j++ ) tempArray[i][j] = -1;
	static const char pjaser[8] = { TORN, HAST, LOPARE, DAM, KUNG, LOPARE, HAST, TORN };
	for( int s=VIT; s<=SVART; s++ ) {
		for( int i=0; i<8; i++ ) {
			tempArray[i][ s == VIT ? 7 : 0 ] = (pjaser[i]<<1)+s;
			tempArray[i][ s == VIT ? 6 : 1 ] = (BONDE<<1)+s;
		}
	}
	std::string temp;
	getline( sparadFil, temp );
	if( temp != "detta är en gamelog" ) {
		// Fail...
	}
	for(;;) {
		sparadFil >> temp;
		char drag[6];
		for (int i=0; i<2; i++ ){
			sparadFil.ignore( 1, ' ' ).read( drag, 5 );
			if( sparadFil.eof() ) goto klar;
			tempArray[drag[3]-'A'][7-(drag[4]-'1')] = tempArray[drag[0]-'A'][7-(drag[1]-'1')];
			tempArray[drag[0]-'A'][7-(drag[1]-'1')] = -1;
			runda++;
		}
	}
	klar:
	// tempArray innehåller nu schack-bordet med rätt pjäser...
	spelare[VIT] = new Spelare( VIT, false );
	spelare[SVART] = new Spelare( SVART, false );
	int antal_pjaser[2] = {0,0};
	for( int i=0; i<8; i++ ) for( int j=0; j<8; j++ ) {
		bool spelare_ = tempArray[i][j] & 1;
		switch( tempArray[i][j]>>1 ){
			case BONDE: pjasArray[i][j] = new Bonde( spelare_, i, j ); break;
			case HAST: pjasArray[i][j] = new Hast( spelare_, i, j ); break;
			case TORN: pjasArray[i][j] = new Torn( spelare_, i, j ); break;
			case LOPARE: pjasArray[i][j] = new Lopare( spelare_, i, j ); break;
			case DAM: pjasArray[i][j] = new Dam( spelare_, i, j ); break;
			case KUNG: pjasArray[i][j] = new Kung( spelare_, i, j ); break;
			default: pjasArray[i][j] = NULL; continue;
		}
		spelare[spelare_]->ptrArray[antal_pjaser[spelare_]++] = pjasArray[i][j];
	}
	vemsDrag = runda % 2 == 0;
	spelare[vemsDrag]->kollaDrag();
	spelare[!vemsDrag]->kollaDrag();
}

/*---------------------------------

Game::~Game( void )
Destruktor.

---------------------------------*/

Game::~Game( void ) {
	delete spelare[VIT];
	delete spelare[SVART];
	if( gamelog.is_open() ) gamelog.close();
	game = NULL;
}

/*---------------------------------

Game::markeraPjas( short x, short y )
Markerar en pjäs som klickats och ritar om markerad + möjliga drag-rutor.
Anropas från musKlick
Argument: x = x-position för musen, y = y-position för musen

---------------------------------*/

void Game::markeraPjas( short x, short y ) {

	// Markera pjäsen. Rita om den + möjliga drag
	markerad = pjasArray[x][y];
	markerad->rita( false, true );

	for( int i = 0; i < 8; i++ ) {
		for( int j = 0; j < 8; j++ ) {
			// Pjäsen kan gå till i,j
			if( markerad->mojligaDrag[i][j] == JA ) {
				video.ritaRektangel( i*60, j*60, 60, 60, MARKERAD_FARG );
			}
			// Hotad pjäs finns på i,j
			else if( markerad->mojligaDrag[i][j] == HOTAR ) {
				video.ritaRektangel( i*60, j*60, 60, 60, HOTAD_FARG );
				if( game->pjasArray[i][j] != NULL ) // NULL kan uppstå vid en passant
					game->pjasArray[i][j]->rita( true, false );
			}
		}
	}
}

/*---------------------------------

Game::avmarkeraPjas( void )
Avmarkerar en pjäs som markerats och ritar om den + tar bort möjliga drag-rutor.
Anropas från musKlick
Argument: x = x-position för musen, y = y-position för musen

---------------------------------*/

void Game::avmarkeraPjas( void ) {
	// Rita om alla rutor och ev pjäser som varit möjliga drag

	for( int i = 0; i < 8; i++ ) {
		for( int j = 0; j < 8; j++ ) {
			// Tom ruta, rita bara rut-färg
			if( markerad->mojligaDrag[i][j] == JA ) {
				video.ritaRektangel( i*60, j*60, 60, 60, RUT_FARG(i,j) );
			}
			// Ockuperad ruta, rita rut-färg + pjäs
			else if( markerad->mojligaDrag[i][j] == HOTAR ) {
				video.ritaRektangel( i*60, j*60, 60, 60, RUT_FARG(i,j) );
				if( game->pjasArray[i][j] != NULL ) // NULL kan uppstå vid en passant
					game->pjasArray[i][j]->rita( true, false );
			}
		}
	}

	markerad->rita( false, false );
}

/*---------------------------------

Game::musKlick( short xpos, short ypos )
Funktion när musen klickas
Argument: xpos = x-position för musen, ypos = y-position för musen

---------------------------------*/

void Game::musKlick( short xpos, short ypos ) {
	short x = xpos / 60;
	short y = ypos / 60;
	short t_x, t_y;
	if ( promovering != NULL ){
		if( promovering->musKlick( xpos, ypos ) ){
			delete promovering;
			promovering = NULL;
			goto promoverat_klart;
		}
	}
	else if ( x < 8 && y < 8 ) {
		if( markerad == NULL && pjasArray[x][y] != NULL && pjasArray[x][y]->spelare == vemsDrag ) {
			//Markera pjäs
			markeraPjas( x, y );
		}
		else if ( markerad != NULL && pjasArray[x][y] == markerad ) {
			//Avmarkera pjäs
			avmarkeraPjas();
			markerad = NULL;
		}
		else if ( markerad && markerad->mojligaDrag[x][y] == JA ) {
			//Gå till en tom ruta

			t_x = markerad->xpos;
			t_y = markerad->ypos;
			avmarkeraPjas(); // höhö

			// Kolla om detta är ett rockad-drag. Det är redan kollat att det inte resulterar i schack.
			if( markerad->typ == KUNG && markerad->flyttad == false && ( x == 2 || x == 6 ) && y == Spelare::undreRad( vemsDrag ) ) {
				int tornFran = x == 2 ? 0 : 7;
				int tornTill = x == 2 ? 3 : 5;
				
				// Flytta först kungen
				video.ritaRektangel( 4*60, y*60, 60, 60, RUT_FARG(4, y) );
				pjasArray[x][y] = markerad;
				pjasArray[4][y] = NULL;
				markerad->xpos = x;
				
				// Sedan tornet
				video.ritaRektangel( tornFran*60, y*60, 60, 60, RUT_FARG(tornFran, y) );
				pjasArray[tornTill][y] = pjasArray[tornFran][y];
				pjasArray[tornFran][y] = NULL;
				pjasArray[tornTill][y]->xpos = tornTill;
				pjasArray[tornTill][y]->flyttad = true;
				pjasArray[tornTill][y]->rita();
				
				goto flytta_pjas;
			}
			else if( game->blirDetSchack( x, y ) == 0 ) {

				flytta_pjas:
				registreraDrag( t_x, t_y, x, y, markerad->typ );

				markerad->flyttad = true;	// behövs för rockad...
				markerad->rita( false, false );
				// om bonden gått längst ned måste den transformas
				if( markerad->typ == BONDE ) {
					if( y == Spelare::undreRad( !vemsDrag ) ) {
						for( int i = 8; i < 16; i++ ) {
							if( spelare[vemsDrag]->ptrArray[i] == markerad ) {
								promovering = new Promovering( markerad );
								return;
							}
						}
					}
				}
				promoverat_klart:
				markerad = NULL;

				// Ny runda, ny persons drag
				runda++;
				vemsDrag = !vemsDrag;

				// Hotad måste göras om
				for( int i = 0; i < 16; i++ ) {
					if( spelare[VIT]->ptrArray[i] ) {
						spelare[VIT]->ptrArray[i]->hotad = false;
					}
					if( spelare[SVART]->ptrArray[i] ) {
						spelare[SVART]->ptrArray[i]->hotad = false;
					}
				}

				spelare[VIT]->kollaDrag();
				spelare[SVART]->kollaDrag();
				((Kung*)(spelare[vemsDrag]->ptrArray[0]))->rockadMojligt();

				// Om kungen är hotad är spelaren i schack
				if( spelare[vemsDrag]->ptrArray[0]->hotad ) {
					spelare[vemsDrag]->schack = true;
				}
				else {
					spelare[vemsDrag]->schack = false;
				}
			}
			else {
				markeraPjas( t_x, t_y );
			}
		}
		else if ( markerad != NULL && pjasArray[x][y] != NULL ) {
			//Har redan en markerad och trycker på en annan pjäs
			if ( vemsDrag != pjasArray[x][y]->spelare ) {
				//Ta pjäs.
				if( markerad->mojligaDrag[x][y] == HOTAR ) {
					t_x = markerad->xpos;
					t_y = markerad->ypos;
					avmarkeraPjas();
					if( game->blirDetSchack( x, y ) == 0 ) {
						spelare[!vemsDrag]->taPjas( pjasArray[x][y] );
						goto flytta_pjas; // >20 rader upp...
					}
					else {
						markeraPjas( t_x, t_y );
					}
				}
			}
			else {
				//Byt markerad
				avmarkeraPjas();
				markeraPjas( x, y );
			}
		}
		else if ( markerad != NULL && markerad->mojligaDrag[x][y] == HOTAR ) {
			//Händer vid en passant
			t_x = markerad->xpos;
			t_y = markerad->ypos;
			avmarkeraPjas();
			if( !game->blirDetSchack( x, y ) ) {
				spelare[!vemsDrag]->taPjas( pjasArray[x][t_y] );
				pjasArray[x][t_y] = NULL;
				video.ritaRektangel( x*60, t_y*60, 60, 60, RUT_FARG(x,t_y) );
				goto flytta_pjas;
			} else {
				markeraPjas( t_x, t_y );
			}
		}
	}

	video.flip();
}

/*--------------------------------

void Game::registreraDrag( char x1, char y1, char x2, char y2, char typ )
Registrerar ett drag, skriver ut det och lägger det till drag-vektorn
Argument: x1-y2 = koordinaterna, typ = pjäsens typ

--------------------------------*/

void Game::registreraDrag( char x1, char y1, char x2, char y2, char typ ) {

	// Rendera texten
	SDL_Color vit = {255,255,255};
	char text[6];
	text[0] = x1 + 'A';
	text[1] = abs(y1-7) + '1';
	text[2] = '-';
	text[3] = x2 + 'A';
	text[4] = abs(y2-7) + '1';
	text[5] = '\0';
	video.renderText( text, 482, (runda-1)*28, vit );

	// Lägg draget i drag-vektorn
	Game::Drag nytt_drag = { vemsDrag, {x1, y1}, {x2, y2}, typ };
	drag.push_back( nytt_drag );

	// Skriv draget i gameloggen
	if( vemsDrag == VIT ) {
		gamelog << runda-(runda/2) << ": ";
	}
	gamelog << text << " ";
	if( vemsDrag == SVART ) {
		gamelog << "\n";
	}
	gamelog.flush();
}

/*---------------------------------

bool Game::blirDetSchack( void )
Kollar om det blir schack när ett drag ska genomföras.
Return: 1 om det blir schack, 0 om det inte blir.

---------------------------------*/

bool Game::blirDetSchack( short x, short y ) {

	// Kolla att det inte blir schack när draget genomförs.
	// Spara den markerades plats, och ta bort den temporärt.

	// ta bort pjäsen som flyttas, spara koordinaterna
	short temp_x = markerad->xpos;
	short temp_y = markerad->ypos;
	pjasArray[temp_x][temp_y] = NULL;
	Pjas* temp_taget_ptr = NULL;
	short temp_i_ptrArray = -1;

	if( pjasArray[x][y] ) {
		// Spara koordinater för tagen pjäs, skapa temp-pekare och ta bort från pjasArray
		//short temp_taget_x = pjasArray[x][y]->xpos;
		//short temp_taget_y = pjasArray[x][y]->ypos;
		temp_taget_ptr = pjasArray[x][y];
		// Vi måste också ta bort den från ptrArray, eftersom kollaDrag använder den.
		for( int i = 0; i < 16; i++ ) {
			if( spelare[!vemsDrag]->ptrArray[i] == temp_taget_ptr ) {
				temp_i_ptrArray = i;
				spelare[!vemsDrag]->ptrArray[i] = NULL;
				break;
			}
		}
		pjasArray[x][y] = NULL;
	}

	// placera pjäsen på det nya draget
	pjasArray[x][y] = markerad;
	markerad->xpos = x;
	markerad->ypos = y;

	// Kolla efter temp-draget, om spelaren är schack.

	// Sätt först flyttande spelarens kung ej hotad
	spelare[vemsDrag]->ptrArray[0]->hotad = 0;

	// Kör kollaDrag för båda spelarna, för att kolla om pjäsen är hotad
	spelare[vemsDrag]->kollaDrag();
	spelare[!vemsDrag]->kollaDrag();

	if( spelare[vemsDrag]->ptrArray[0]->hotad ) {
		// Spelaren som drar är/blir i schack, flytta tillbaka och avbryt flyttningen

		// Ta bort den temporära förflyttningen, återställ koordinaterna
		pjasArray[x][y] = NULL;
		markerad->xpos = temp_x;
		markerad->ypos = temp_y;
		pjasArray[temp_x][temp_y] = markerad;
		if( temp_taget_ptr ) {
			pjasArray[temp_taget_ptr->xpos][temp_taget_ptr->ypos] = temp_taget_ptr;
			spelare[!vemsDrag]->ptrArray[temp_i_ptrArray] = temp_taget_ptr;
		}

		// Ta bort alla spelares "hotad"
		for( int i = 0; i < 16; i++ ) {
			if( spelare[VIT]->ptrArray[i] ) {
				spelare[VIT]->ptrArray[i]->hotad = false;
			}
			if( spelare[SVART]->ptrArray[i] ) {
				spelare[SVART]->ptrArray[i]->hotad = false;
			}
		}

		// Fyll mojligaDrag för pjäserna igen
		spelare[VIT]->kollaDrag();
		spelare[SVART]->kollaDrag();

		// Det blev schack, returna 1
		return 1;

	}
	else {
		video.ritaRektangel( temp_x*60, temp_y*60, 60, 60, RUT_FARG(temp_x,temp_y) );
		// Blir inte schack, draget har genomförts!
		// Om en pjäs togs, ta bort ptrArray-referensen till den.
		if( temp_taget_ptr ) {
			delete temp_taget_ptr;
		}

		// Det blev inte schack, returna 0
		return 0;
	}
}

/*---------------------------------

Game::Promovering::Promovering( Pjas* pjas )
Körs när man har flyttat en bonde ut till kanten.
Ritar upp kandidater (nya pjäser) till höger som man kan klicka på.
Argument: pjas = bonden som är i kanten.

---------------------------------*/

Game::Promovering::Promovering( Pjas* pjas ) : pjas(pjas) {
	ritatUnder = SDL_CreateRGBSurface( SDL_SWSURFACE, 60, 60*4, 32, 0xff, 0xff00, 0xff0000, 0xff000000 );
	SDL_Rect underRect = { 500, 100, 60, 60*4 };
	SDL_BlitSurface( video.screen, &underRect, ritatUnder, NULL );

	//Dessa ska inte frias, eftersom de bara är referenser till surfaces i video
	SDL_Surface* damBild = video.loadImage( pjas->spelare == VIT ? "vit_dam.bmp" : "svart_dam.bmp" );
	SDL_Surface* tornBild = video.loadImage( pjas->spelare == VIT ? "vit_torn.bmp" : "svart_torn.bmp" );
	SDL_Surface* hastBild = video.loadImage( pjas->spelare == VIT ? "vit_hast.bmp" : "svart_hast.bmp" );
	SDL_Surface* lopareBild = video.loadImage( pjas->spelare == VIT ? "vit_lopare.bmp" : "svart_lopare.bmp" );

	video.ritaBild( 500, 100, 60, 60, damBild );
	video.ritaBild( 500, 160, 60, 60, tornBild );
	video.ritaBild( 500, 220, 60, 60, hastBild );
	video.ritaBild( 500, 280, 60, 60, lopareBild );
}

/*---------------------------------
bool Game::Promovering::musKlick( short xpos, short ypos )
Kollar om man klickade på en ny pjäs som ska bildas,
skapar isåfall den och ersätter den gamla.
Return: true om man bytte ut pjäsen, false om klicket var värdelöst/utanför

---------------------------------*/

bool Game::Promovering::musKlick( short xpos, short ypos ){
	if( xpos < 500 || xpos > 560 || ypos < 100 || ypos > 340 ) return false;

	Pjas* nyaPjasen;
	switch( (ypos-100)/60 ){
		case 0: nyaPjasen = new Dam( pjas->spelare, pjas->xpos, pjas->ypos ); break;
		case 1: nyaPjasen = new Torn( pjas->spelare, pjas->xpos, pjas->ypos ); break;
		case 2: nyaPjasen = new Hast( pjas->spelare, pjas->xpos, pjas->ypos ); break;
		case 3: nyaPjasen = new Lopare( pjas->spelare, pjas->xpos, pjas->ypos ); break;
	}

	for( int i = 8; i < 16; i++ ) {
		if( game->spelare[game->vemsDrag]->ptrArray[i] == pjas ) {
			game->spelare[game->vemsDrag]->ptrArray[i] = nyaPjasen;
			break;
		}
	}
	nyaPjasen->flyttad = true;
	nyaPjasen->rita( false, false );
	delete pjas;
	return true;
}

/*---------------------------------

Game::Promovering::~Promovering()
Körs när man har valt en ny pjästyp.
Tar bort pjäsbilderna till höger och ritar upp det igen som var bakom.

---------------------------------*/
Game::Promovering::~Promovering() {
	SDL_Rect underRect = { 500, 100, 60, 60*4 };
	SDL_BlitSurface( ritatUnder, NULL, video.screen, &underRect );
	SDL_FreeSurface( ritatUnder );
}
